#include <stdio.h>
#include <signal.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdint.h>
#include <iostream>
#include "Role.h"

#define SO_FILE "./libHotUpdate.so"

int replaceFunction(void* pSoHandle, const char* pSymbol) {
    void* pNewAddr = dlsym(pSoHandle, pSymbol);
    if (nullptr == pNewAddr) {
        fprintf(stderr, "get new addr, Error: %s\n" ,strerror(errno));
        return -1;
    }
    printf("address of new function: %s ,addr:%x\n\n", pSymbol, pNewAddr);
    void* pOldAddr = dlsym(nullptr, pSymbol);
    if (nullptr == pOldAddr) {
        fprintf(stderr, "get old addr, Error: %s\n" ,strerror(errno));
        return -1;
    }
    printf("address of old function: %s ,addr:%x\n\n", pSymbol, pOldAddr);

    size_t iPageSize = sysconf(_SC_PAGE_SIZE);
    uintptr_t pAlignAddr = (uintptr_t)(pOldAddr) & (~(iPageSize - 1));
    if (mprotect((void*)(pAlignAddr), 2 * iPageSize, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
        fprintf(stderr, "mprotect old addr, Error: %s\n" ,strerror(errno));
        return -1;
    }

    // 以下只支持64系统
    memset(static_cast<char*>(pOldAddr), 0x48, 1);
    memset(static_cast<char*>(pOldAddr)+1, 0xb8, 1);
    memcpy(static_cast<char*>(pOldAddr)+2, &pNewAddr, 8);
    memset(static_cast<char*>(pOldAddr)+10, 0xff, 1);
    memset(static_cast<char*>(pOldAddr)+11, 0xe0, 1);
    if (mprotect((void*)(pAlignAddr), 2 * iPageSize, PROT_READ | PROT_EXEC) != 0) {
        fprintf(stderr, "mprotect2 old addr, Error: %s\n" ,strerror(errno));
    }

    return 0;
}

void signalHandle(int) {
    void* pSoHandle = dlopen(SO_FILE, RTLD_NOW);
    if (nullptr == pSoHandle) {
        fprintf(stderr, "Error:%s\n", dlerror());
        exit(-1);
    }

    replaceFunction(pSoHandle, "_ZN4Role12getClassNameB5cxx11Ev");
    replaceFunction(pSoHandle, "_ZN4Role15testVirtualFuncB5cxx11Ev");
    replaceFunction(pSoHandle, "_ZN4Role8setValueEi");
    replaceFunction(pSoHandle, "_ZN4Role14testStaticFuncERS_");
    replaceFunction(pSoHandle, "_Z25modifyRolePrivateVariableR4Role");
    //replaceFunction(so_handle, "");
}

int main(int argc, const char **argv) {
    struct sigaction stSa;
    stSa.sa_handler = signalHandle;
    sigemptyset(&stSa.sa_mask);
    stSa.sa_flags = SA_RESTART;

    if (sigaction(SIGUSR1, &stSa, nullptr) == -1) {
        perror("sigaction error");
        return -1;
    }

    int i = 0;
    Role stRole;
    while (++i) {
        std::cout << "-------------------------" << i << "-------------------" << std::endl;
        std::cout << "ClassName:" << stRole.getClassName() << std::endl;
        std::cout << "setValue:5"  << std::endl;
        stRole.setValue(5);
        std::cout << "getValue:" << stRole.getNum() << std::endl;
        std::cout << "test virtual:" << stRole.testVirtualFunc() << std::endl;
        std::cout << "test static" << std::endl;
        Role::testStaticFunc(stRole);
        std::cout << "getValue:" << stRole.getNum() << std::endl;
        std::cout << "test modify private" << std::endl;
        modifyRolePrivateVariable(stRole);
        sleep(3);
    }
    return 0;
}
